{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c01a71aa",
   "metadata": {},
   "source": [
    "| [03_data_science/03_Numpy方法.ipynb](https://github.com/shibing624/python-tutorial/blob/master/03_data_science/03_Numpy方法.ipynb)  | Numpy 方法  |[Open In Colab](https://colab.research.google.com/github/shibing624/python-tutorial/blob/master/03_data_science/03_Numpy方法.ipynb) |\n",
    "\n",
    "# Numpy方法\n",
    "\n",
    "Numpy的常用方法。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "1e10defe",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2, 3],\n",
       "       [4, 5, 6, 7]])"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([[0, 1, 2, 3], [4, 5, 6, 7]])\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b5fef686",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 2 3]\n",
      "[4 5 6 7]\n"
     ]
    }
   ],
   "source": [
    "for row in a:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69cd933c",
   "metadata": {},
   "source": [
    "所有元素的迭代器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "0a469912",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "for i in a.flat:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a15daca8",
   "metadata": {},
   "source": [
    "## 矩阵转置："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bcbcf25d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0 1 2 3]\n",
      " [4 5 6 7]]\n",
      "[[0 4]\n",
      " [1 5]\n",
      " [2 6]\n",
      " [3 7]]\n",
      "[[0 1 2 3]\n",
      " [4 5 6 7]]\n",
      "(2, 4)\n"
     ]
    }
   ],
   "source": [
    "print(a)\n",
    "print(a.T)\n",
    "print(a)\n",
    "print(a.shape)  # 数组形状 (m,n,o,...)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f803c8be",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n",
      "[[0 1]\n",
      " [2 3]\n",
      " [4 5]\n",
      " [6 7]]\n",
      "(4, 2)\n"
     ]
    }
   ],
   "source": [
    "print(a.size)  # 数组元素数\n",
    "a.resize((4, 2))\n",
    "print(a)\n",
    "print(a.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1311e0de",
   "metadata": {},
   "source": [
    "## squeeze\n",
    "\n",
    "把shape为1的维度去掉："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e33958b3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.arange(10).reshape(1,10)\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "cd0b942c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 10)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2e2f9ad6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.squeeze(a)\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "914b5a13",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(10,)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc29356d",
   "metadata": {},
   "source": [
    "再举个多维的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e4cac692",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[0 1 2 3 4]\n",
      "  [5 6 7 8 9]]]\n",
      "(1, 2, 5)\n"
     ]
    }
   ],
   "source": [
    "a = np.arange(10).reshape(1, 2, 5)\n",
    "print(a)\n",
    "\n",
    "print(a.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b92af824",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 5)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.squeeze(a)\n",
    "b.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "9dca87c5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 2, 5)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d37681d",
   "metadata": {},
   "source": [
    "## 复制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "dee86099",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1,  1,  2,  3],\n",
       "       [ 4,  5,  6,  7]])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[0, 1, 2, 3], [4, 5, 6, 7]])\n",
    "b = a.copy()\n",
    "b[0][0] = -1\n",
    "\n",
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9ac0f221",
   "metadata": {},
   "source": [
    "填充："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "ab018170",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[9, 9, 9, 9],\n",
       "       [9, 9, 9, 9]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.fill(9)\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "c67a34a4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[0, 1, 2, 3], [4, 5, 6, 7]]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转化为列表：\n",
    "a.tolist()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12413015",
   "metadata": {},
   "source": [
    "## 复数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "fb982d09",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1. 3. 5.]\n",
      "[2. 4. 6.]\n"
     ]
    }
   ],
   "source": [
    "# 实部：\n",
    "b = np.array([1 + 2j, 3 + 4j, 5 + 6j])\n",
    "c = b.real\n",
    "print(c)\n",
    "\n",
    "# 虚部：\n",
    "d = b.imag\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "1729c329",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.-2.j 3.-4.j 5.-6.j]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 共轭：\n",
    "print(b.conj())\n",
    "\n",
    "# 保存成文本：\n",
    "a.dump(\"file.txt\")\n",
    "\n",
    "\n",
    "import os\n",
    "os.path.exists('file.txt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "26327ee8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'\\x80\\x02cnumpy.core.multiarray\\n_reconstruct\\nq\\x00cnumpy\\nndarray\\nq\\x01K\\x00\\x85q\\x02c_codecs\\nencode\\nq\\x03X\\x01\\x00\\x00\\x00bq\\x04X\\x06\\x00\\x00\\x00latin1q\\x05\\x86q\\x06Rq\\x07\\x87q\\x08Rq\\t(K\\x01K\\x02K\\x04\\x86q\\ncnumpy\\ndtype\\nq\\x0bX\\x02\\x00\\x00\\x00i8q\\x0c\\x89\\x88\\x87q\\rRq\\x0e(K\\x03X\\x01\\x00\\x00\\x00<q\\x0fNNNJ\\xff\\xff\\xff\\xffJ\\xff\\xff\\xff\\xffK\\x00tq\\x10b\\x89h\\x03X@\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x06\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x07\\x00\\x00\\x00\\x00\\x00\\x00\\x00q\\x11h\\x05\\x86q\\x12Rq\\x13tq\\x14b.'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "with open('file.txt', 'rb') as f:\n",
    "    m = f.read()\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "de7b70d7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'\\x80\\x02cnumpy.core.multiarray\\n_reconstruct\\nq\\x00cnumpy\\nndarray\\nq\\x01K\\x00\\x85q\\x02c_codecs\\nencode\\nq\\x03X\\x01\\x00\\x00\\x00bq\\x04X\\x06\\x00\\x00\\x00latin1q\\x05\\x86q\\x06Rq\\x07\\x87q\\x08Rq\\t(K\\x01K\\x02K\\x04\\x86q\\ncnumpy\\ndtype\\nq\\x0bX\\x02\\x00\\x00\\x00i8q\\x0c\\x89\\x88\\x87q\\rRq\\x0e(K\\x03X\\x01\\x00\\x00\\x00<q\\x0fNNNJ\\xff\\xff\\xff\\xffJ\\xff\\xff\\xff\\xffK\\x00tq\\x10b\\x89h\\x03X@\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x06\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x07\\x00\\x00\\x00\\x00\\x00\\x00\\x00q\\x11h\\x05\\x86q\\x12Rq\\x13tq\\x14b.'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 字符串：\n",
    "a.dumps()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "b2e98be7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 写入文件\n",
    "a.tofile('foo.csv', sep=',', format=\"%s\")\n",
    "os.path.exists('foo.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "402cdea7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'0,1,2,3,4,5,6,7'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "with open('foo.csv') as f:\n",
    "    m = f.read()\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29f0b4ec",
   "metadata": {},
   "source": [
    "## 排序\n",
    "非零元素的索引："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "d1403f3b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2, 3],\n",
       "       [4, 5, 6, 7]])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = a.nonzero()\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "df696210",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0, 0, 0, 1, 1, 1, 1]), array([1, 2, 3, 0, 1, 2, 3]))"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "c182dcfd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 7])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 排序：\n",
    "b = np.array([3, 2, 7, 4, 1])\n",
    "b.sort()\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "9b38c37b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2, 0, 1])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 排序的索引位置：\n",
    "b = np.array([2, 3, 1])\n",
    "b.argsort(axis=-1)  # array([2, 0, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "4dd272bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 3]\n"
     ]
    }
   ],
   "source": [
    "# 将 b 插入 a 中的索引，使得 a 保持有序：\n",
    "a = np.array([1, 3, 4, 6])\n",
    "b = np.array([0, 2, 5])\n",
    "print(a.searchsorted(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5be293fb",
   "metadata": {},
   "source": [
    "## 元素的数学操作\n",
    "clip，限制在一定范围："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "f0cbfe2c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[2, 1, 2],\n",
       "       [2, 1, 2]])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[4, 1, 3], [2, 1, 5]])\n",
    "a.clip(0, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "7ae51c4e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4, 1, 3],\n",
       "       [2, 1, 5]])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "11ca1ff8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.34, 2.45, 2.56])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 近似：\n",
    "a = np.array([1.344, 2.449, 2.558])\n",
    "b = a.round(decimals=2)\n",
    "b  # [ 1.34  2.45  2.56]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "c154cb09",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# 是否全部非零：\n",
    "print(a.all())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "79781937",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.remove('foo.csv')\n",
    "os.remove('file.txt')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c127256",
   "metadata": {},
   "source": [
    "## 数组与字符串的转换\n",
    "\n",
    "tobytes 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "7c3b5db1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n",
      "b'\\x01\\x02\\x03\\x04'\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2], [3, 4]], dtype=np.uint8)\n",
    "print(a)\n",
    "print(a.tobytes())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c80ffb3",
   "metadata": {},
   "source": [
    "frombuffer 函数\n",
    "\n",
    "可以使用 frombuffer 函数从字符串中读出数据，不过要指定类型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "131b667d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4], dtype=uint8)"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = a.tobytes()\n",
    "b = np.frombuffer(s, dtype=np.uint8)\n",
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca036381",
   "metadata": {},
   "source": [
    "此时，返回的数组是一维的，需要重新设定维度："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "2b0fffc9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4]], dtype=uint8)"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.shape = 2, 2\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "c5d0cd47",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4]], dtype=uint8)"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 可以使用reshape：\n",
    "b = np.frombuffer(s, dtype=np.uint8).reshape(2, 2)\n",
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34d176ab",
   "metadata": {},
   "source": [
    "## 文本中读取数组\n",
    "\n",
    "对于读文本文件，推荐使用:\n",
    "- loadtxt\n",
    "- genfromtxt\n",
    "- savetxt\n",
    "\n",
    "\n",
    "对于二进制文本文件，推荐使用\n",
    "- save\n",
    "- load\n",
    "- savez\n",
    "\n",
    "### loadtxt 函数\n",
    "```\n",
    "loadtxt(fname, dtype=<type 'float'>,\n",
    "        comments='#', delimiter=None,\n",
    "        converters=None, skiprows=0,\n",
    "        usecols=None, unpack=False, ndmin=0)     \n",
    "```\n",
    "- loadtxt 有很多可选参数，其中 delimiter 就是刚才用到的分隔符参数。\n",
    "- skiprows 参数表示忽略开头的行数，可以用来读写含有标题的文本\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "cb1ff57d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[101,   0],\n",
       "       [101,   1],\n",
       "       [101,   2],\n",
       "       ...,\n",
       "       [101, 997],\n",
       "       [101, 998],\n",
       "       [101, 999]])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_file = \"../data/numpy/data.txt\"\n",
    "c = np.loadtxt(data_file, dtype=int)\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "b00a0050",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1000, 2)"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0989080c",
   "metadata": {},
   "source": [
    "### genfromtxt\n",
    "genfromtxt 函数功能更为全面，\n",
    "能处理更多的情况，但相应的速度和效率会慢一些。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "3b3622de",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function genfromtxt in module numpy:\n",
      "\n",
      "genfromtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None, usecols=None, names=None, excludelist=None, deletechars=\" !#$%&'()*+,-./:;<=>?@[\\\\]^{|}~\", replace_space='_', autostrip=False, case_sensitive=True, defaultfmt='f%i', unpack=None, usemask=False, loose=True, invalid_raise=True, max_rows=None, encoding='bytes', *, like=None)\n",
      "    Load data from a text file, with missing values handled as specified.\n",
      "    \n",
      "    Each line past the first `skip_header` lines is split at the `delimiter`\n",
      "    character, and characters following the `comments` character are discarded.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    fname : file, str, pathlib.Path, list of str, generator\n",
      "        File, filename, list, or generator to read.  If the filename\n",
      "        extension is `.gz` or `.bz2`, the file is first decompressed. Note\n",
      "        that generators must return byte strings. The strings\n",
      "        in a list or produced by a generator are treated as lines.\n",
      "    dtype : dtype, optional\n",
      "        Data type of the resulting array.\n",
      "        If None, the dtypes will be determined by the contents of each\n",
      "        column, individually.\n",
      "    comments : str, optional\n",
      "        The character used to indicate the start of a comment.\n",
      "        All the characters occurring on a line after a comment are discarded\n",
      "    delimiter : str, int, or sequence, optional\n",
      "        The string used to separate values.  By default, any consecutive\n",
      "        whitespaces act as delimiter.  An integer or sequence of integers\n",
      "        can also be provided as width(s) of each field.\n",
      "    skiprows : int, optional\n",
      "        `skiprows` was removed in numpy 1.10. Please use `skip_header` instead.\n",
      "    skip_header : int, optional\n",
      "        The number of lines to skip at the beginning of the file.\n",
      "    skip_footer : int, optional\n",
      "        The number of lines to skip at the end of the file.\n",
      "    converters : variable, optional\n",
      "        The set of functions that convert the data of a column to a value.\n",
      "        The converters can also be used to provide a default value\n",
      "        for missing data: ``converters = {3: lambda s: float(s or 0)}``.\n",
      "    missing : variable, optional\n",
      "        `missing` was removed in numpy 1.10. Please use `missing_values`\n",
      "        instead.\n",
      "    missing_values : variable, optional\n",
      "        The set of strings corresponding to missing data.\n",
      "    filling_values : variable, optional\n",
      "        The set of values to be used as default when the data are missing.\n",
      "    usecols : sequence, optional\n",
      "        Which columns to read, with 0 being the first.  For example,\n",
      "        ``usecols = (1, 4, 5)`` will extract the 2nd, 5th and 6th columns.\n",
      "    names : {None, True, str, sequence}, optional\n",
      "        If `names` is True, the field names are read from the first line after\n",
      "        the first `skip_header` lines.  This line can optionally be proceeded\n",
      "        by a comment delimiter. If `names` is a sequence or a single-string of\n",
      "        comma-separated names, the names will be used to define the field names\n",
      "        in a structured dtype. If `names` is None, the names of the dtype\n",
      "        fields will be used, if any.\n",
      "    excludelist : sequence, optional\n",
      "        A list of names to exclude. This list is appended to the default list\n",
      "        ['return','file','print']. Excluded names are appended an underscore:\n",
      "        for example, `file` would become `file_`.\n",
      "    deletechars : str, optional\n",
      "        A string combining invalid characters that must be deleted from the\n",
      "        names.\n",
      "    defaultfmt : str, optional\n",
      "        A format used to define default field names, such as \"f%i\" or \"f_%02i\".\n",
      "    autostrip : bool, optional\n",
      "        Whether to automatically strip white spaces from the variables.\n",
      "    replace_space : char, optional\n",
      "        Character(s) used in replacement of white spaces in the variables\n",
      "        names. By default, use a '_'.\n",
      "    case_sensitive : {True, False, 'upper', 'lower'}, optional\n",
      "        If True, field names are case sensitive.\n",
      "        If False or 'upper', field names are converted to upper case.\n",
      "        If 'lower', field names are converted to lower case.\n",
      "    unpack : bool, optional\n",
      "        If True, the returned array is transposed, so that arguments may be\n",
      "        unpacked using ``x, y, z = genfromtxt(...)``.  When used with a\n",
      "        structured data-type, arrays are returned for each field.\n",
      "        Default is False.\n",
      "    usemask : bool, optional\n",
      "        If True, return a masked array.\n",
      "        If False, return a regular array.\n",
      "    loose : bool, optional\n",
      "        If True, do not raise errors for invalid values.\n",
      "    invalid_raise : bool, optional\n",
      "        If True, an exception is raised if an inconsistency is detected in the\n",
      "        number of columns.\n",
      "        If False, a warning is emitted and the offending lines are skipped.\n",
      "    max_rows : int,  optional\n",
      "        The maximum number of rows to read. Must not be used with skip_footer\n",
      "        at the same time.  If given, the value must be at least 1. Default is\n",
      "        to read the entire file.\n",
      "    \n",
      "        .. versionadded:: 1.10.0\n",
      "    encoding : str, optional\n",
      "        Encoding used to decode the inputfile. Does not apply when `fname` is\n",
      "        a file object.  The special value 'bytes' enables backward compatibility\n",
      "        workarounds that ensure that you receive byte arrays when possible\n",
      "        and passes latin1 encoded strings to converters. Override this value to\n",
      "        receive unicode arrays and pass strings as input to converters.  If set\n",
      "        to None the system default is used. The default value is 'bytes'.\n",
      "    \n",
      "        .. versionadded:: 1.14.0\n",
      "    like : array_like\n",
      "        Reference object to allow the creation of arrays which are not\n",
      "        NumPy arrays. If an array-like passed in as ``like`` supports\n",
      "        the ``__array_function__`` protocol, the result will be defined\n",
      "        by it. In this case, it ensures the creation of an array object\n",
      "        compatible with that passed in via this argument.\n",
      "    \n",
      "        .. note::\n",
      "            The ``like`` keyword is an experimental feature pending on\n",
      "            acceptance of :ref:`NEP 35 <NEP35>`.\n",
      "    \n",
      "        .. versionadded:: 1.20.0\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    out : ndarray\n",
      "        Data read from the text file. If `usemask` is True, this is a\n",
      "        masked array.\n",
      "    \n",
      "    See Also\n",
      "    --------\n",
      "    numpy.loadtxt : equivalent function when no data is missing.\n",
      "    \n",
      "    Notes\n",
      "    -----\n",
      "    * When spaces are used as delimiters, or when no delimiter has been given\n",
      "      as input, there should not be any missing data between two fields.\n",
      "    * When the variables are named (either by a flexible dtype or with `names`),\n",
      "      there must not be any header in the file (else a ValueError\n",
      "      exception is raised).\n",
      "    * Individual values are not stripped of spaces by default.\n",
      "      When using a custom converter, make sure the function does remove spaces.\n",
      "    \n",
      "    References\n",
      "    ----------\n",
      "    .. [1] NumPy User Guide, section `I/O with NumPy\n",
      "           <https://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html>`_.\n",
      "    \n",
      "    Examples\n",
      "    --------\n",
      "    >>> from io import StringIO\n",
      "    >>> import numpy as np\n",
      "    \n",
      "    Comma delimited file with mixed dtype\n",
      "    \n",
      "    >>> s = StringIO(u\"1,1.3,abcde\")\n",
      "    >>> data = np.genfromtxt(s, dtype=[('myint','i8'),('myfloat','f8'),\n",
      "    ... ('mystring','S5')], delimiter=\",\")\n",
      "    >>> data\n",
      "    array((1, 1.3, b'abcde'),\n",
      "          dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', 'S5')])\n",
      "    \n",
      "    Using dtype = None\n",
      "    \n",
      "    >>> _ = s.seek(0) # needed for StringIO example only\n",
      "    >>> data = np.genfromtxt(s, dtype=None,\n",
      "    ... names = ['myint','myfloat','mystring'], delimiter=\",\")\n",
      "    >>> data\n",
      "    array((1, 1.3, b'abcde'),\n",
      "          dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', 'S5')])\n",
      "    \n",
      "    Specifying dtype and names\n",
      "    \n",
      "    >>> _ = s.seek(0)\n",
      "    >>> data = np.genfromtxt(s, dtype=\"i8,f8,S5\",\n",
      "    ... names=['myint','myfloat','mystring'], delimiter=\",\")\n",
      "    >>> data\n",
      "    array((1, 1.3, b'abcde'),\n",
      "          dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', 'S5')])\n",
      "    \n",
      "    An example with fixed-width columns\n",
      "    \n",
      "    >>> s = StringIO(u\"11.3abcde\")\n",
      "    >>> data = np.genfromtxt(s, dtype=None, names=['intvar','fltvar','strvar'],\n",
      "    ...     delimiter=[1,3,5])\n",
      "    >>> data\n",
      "    array((1, 1.3, b'abcde'),\n",
      "          dtype=[('intvar', '<i8'), ('fltvar', '<f8'), ('strvar', 'S5')])\n",
      "    \n",
      "    An example to show comments\n",
      "    \n",
      "    >>> f = StringIO('''\n",
      "    ... text,# of chars\n",
      "    ... hello world,11\n",
      "    ... numpy,5''')\n",
      "    >>> np.genfromtxt(f, dtype='S12,S12', delimiter=',')\n",
      "    array([(b'text', b''), (b'hello world', b'11'), (b'numpy', b'5')],\n",
      "      dtype=[('f0', 'S12'), ('f1', 'S12')])\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(np.genfromtxt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "7c29efa6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[101.,   0.],\n",
       "       [101.,   1.],\n",
       "       [101.,   2.],\n",
       "       ...,\n",
       "       [101., 997.],\n",
       "       [101., 998.],\n",
       "       [101., 999.]])"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g = np.genfromtxt(data_file)\n",
    "g"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca2035fd",
   "metadata": {},
   "source": [
    "当然，还有很笨的写法：\n",
    "\n",
    "首先将数据转化成一个列表组成的列表，再将这个列表转换为数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "30fa647d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[101.,   0.],\n",
       "       [101.,   1.],\n",
       "       [101.,   2.],\n",
       "       ...,\n",
       "       [101., 997.],\n",
       "       [101., 998.],\n",
       "       [101., 999.]])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = []\n",
    "\n",
    "with open(data_file) as f:\n",
    "    # 每次读一行\n",
    "    for line in f:\n",
    "        fileds = line.split()\n",
    "        row_data = [float(x) for x in fileds]\n",
    "        data.append(row_data)\n",
    "\n",
    "data = np.array(data)\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "9c4b916d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[   1,    1, 2000,   13],\n",
       "       [   4,    1, 2000,   55]])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# loadtxt 的更多特性\n",
    "sp_file = '../data/numpy/special_data.txt'\n",
    "data = np.loadtxt(sp_file,\n",
    "                  dtype=int,\n",
    "                  comments='%',  # 百分号为注释符\n",
    "                  delimiter=',',  # 逗号分割\n",
    "                  skiprows=1,  # 忽略第一行\n",
    "                  usecols=(0, 1, 2, 4))  # 指定使用哪几列数据\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51da3bf7",
   "metadata": {},
   "source": [
    "### loadtxt 自定义转换方法\n",
    "\n",
    "loadtxt返回的值为字节字符串bytes, 对字符串解码用函数decode(‘asii’)，变成str格式："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "409b45b7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[datetime.datetime(2020, 1, 1, 0, 0), 2.3, 3.2],\n",
       "       [datetime.datetime(2021, 1, 1, 0, 0), 6.1, 3.1]], dtype=object)"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import datetime\n",
    "\n",
    "\n",
    "def date_converter(s):\n",
    "    return datetime.datetime.strptime(s.decode('ascii'), \"%Y-%m-%d\")\n",
    "\n",
    "date_file = '../data/numpy/datetime_data.txt'\n",
    "data = np.loadtxt(date_file,\n",
    "                  dtype=object,  # 数据类型为对象\n",
    "                  converters={0: date_converter,  # 第一列使用自定义转换方法\n",
    "                              1: float,  # 第二第三列使用浮点数转换\n",
    "                              2: float})\n",
    "\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db9c3652",
   "metadata": {},
   "source": [
    "### 将数组写入文件\n",
    "\n",
    "savetxt 可以将数组写入文件，默认使用科学计数法的形式保存："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "bb2d0d45",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2, 3)\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2, 3], [5, 6, 7]])\n",
    "np.savetxt('out.txt', a)\n",
    "\n",
    "# 可以用类似printf 的方式指定输出的格式：\n",
    "a = np.array([[1, 2, 3], [5, 6, 7]])\n",
    "print(a.shape)\n",
    "\n",
    "np.savetxt('out_fmt.txt', a, fmt=['%d'] * a.shape[1], newline='\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "3f71956f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n",
      "\n",
      "5 6 7\n",
      "\n"
     ]
    }
   ],
   "source": [
    "with open('out_fmt.txt') as f:\n",
    "    for line in f:\n",
    "        print(line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "62647d83",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[['1' 'a']\n",
      " ['2' 'b']\n",
      " ['3' 'c']\n",
      " ['4' 'd']\n",
      " ['5' 'e']]\n"
     ]
    }
   ],
   "source": [
    "m = zip([1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e'])\n",
    "m = list(m)\n",
    "\n",
    "z = np.array(m)\n",
    "print(z)\n",
    "\n",
    "np.savetxt('out_str_fmt.txt', z, fmt=['%s'] * z.shape[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "7d4e14bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.remove('out.txt')\n",
    "os.remove('out_fmt.txt')\n",
    "os.remove('out_str_fmt.txt')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b05f8b0",
   "metadata": {},
   "source": [
    "### Numpy 二进制格式\n",
    "保存的方法：\n",
    "\n",
    "- save(file, arr) 保存单个数组，.npy 格式\n",
    "- savez(file, *args, **kwds) 保存多个数组，无压缩的 .npz 格式\n",
    "- savez_compressed(file, *args, **kwds) 保存多个数组，有压缩的 .npz 格式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "9e3dc46a",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([[1, 2], [3, 4]])\n",
    "np.save('out.npy', a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "abd41647",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 二进制与文本大小比较\n",
    "a = np.arange(10000.)\n",
    "np.savetxt('a.txt', a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "461e4be8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "250000\n",
      "80128\n"
     ]
    }
   ],
   "source": [
    "# 查看大小：\n",
    "import os\n",
    "\n",
    "print(os.stat('a.txt').st_size)\n",
    "\n",
    "# 保存为二进制\n",
    "np.save('a.npy', a)\n",
    "print(os.stat('a.npy').st_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d869cb1",
   "metadata": {},
   "source": [
    "二进制文件大约是文本文件的三分之一。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "eebf8862",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n",
      "[990 991 992 993 994 995 996 997 998 999]\n",
      "(1000,)\n"
     ]
    }
   ],
   "source": [
    "# 保存多个数组\n",
    "a = np.array([[1, 2], [3, 4]])\n",
    "b = np.arange(1000)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "4b8777ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.savez('ab.npz', a=a, b=b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "eb407142",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8522\n",
      "KeysView(<numpy.lib.npyio.NpzFile object at 0x7fa5b9fc44c0>)\n",
      "['a', 'b']\n",
      "(2, 2)\n",
      "(1000,)\n"
     ]
    }
   ],
   "source": [
    "# 加载数据\n",
    "ab = np.load('ab.npz')\n",
    "print(os.stat('ab.npz').st_size)  # file size\n",
    "print(ab.keys())\n",
    "print(list(ab.keys()))\n",
    "\n",
    "print(ab['a'].shape)\n",
    "print(ab['b'].shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "17f2feb3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1951\n"
     ]
    }
   ],
   "source": [
    "np.savez_compressed('ab_compressed.npz', a=a, b=b)\n",
    "print(os.stat('ab_compressed.npz').st_size)  # file size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "25fed167",
   "metadata": {},
   "outputs": [],
   "source": [
    "os.remove('out.npy')\n",
    "os.remove('a.txt')\n",
    "os.remove('a.npy')\n",
    "os.remove('ab.npz')\n",
    "os.remove('ab_compressed.npz')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aff76d86",
   "metadata": {},
   "source": [
    "## 生成数组的函数\n",
    "\n",
    "\n",
    "### arange 生成数组，[start,stop)\n",
    "\n",
    "arange(start, stop=None, step=1, dtype=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "7144e105",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(5)  # [0 1 2 3 4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "fc501e3a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.        , 0.78539816, 1.57079633, 2.35619449, 3.14159265,\n",
       "       3.92699082, 4.71238898, 5.49778714])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.arange(0, 2 * np.pi, np.pi / 4)\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4755d64e",
   "metadata": {},
   "source": [
    "### linspace\n",
    "linspace(start,stop,N)\n",
    "\n",
    "产生N个等距分布在[start,stop]间的元素组成的数组，包括start,stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "3c8f8d29",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.  , 0.25, 0.5 , 0.75, 1.  ])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linspace(0, 1, 5)  # [ 0.    0.25  0.5   0.75  1.  ]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb50b292",
   "metadata": {},
   "source": [
    "### logspace\n",
    "logspace(start, stop, N)\n",
    "\n",
    "产生 N 个对数等距分布的数组，默认以10为底："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "8584f847",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.        ,  1.77827941,  3.16227766,  5.62341325, 10.        ])"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.logspace(0, 1, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93825447",
   "metadata": {},
   "source": [
    "产生的值为$\\left[10^0, 10^{0.25},10^{0.5},10^{0.75},10^1\\right]$。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a806f1bf",
   "metadata": {},
   "source": [
    "### meshgrid\n",
    "\n",
    "二维平面中生成一个网格"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "0796e90e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-1.  -0.5  0.   0.5  1. ]\n",
      "[[-1.  -0.5  0.   0.5  1. ]\n",
      " [-1.  -0.5  0.   0.5  1. ]\n",
      " [-1.  -0.5  0.   0.5  1. ]\n",
      " [-1.  -0.5  0.   0.5  1. ]\n",
      " [-1.  -0.5  0.   0.5  1. ]]\n"
     ]
    }
   ],
   "source": [
    "x_ticks = np.linspace(-1, 1, 5)\n",
    "y_ticks = np.linspace(-1, 1, 5)\n",
    "x, y = np.meshgrid(x_ticks, y_ticks)\n",
    "print(x_ticks)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e542a772",
   "metadata": {},
   "source": [
    "### 图例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "87a85ffc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-10.   -9.6  -9.2  -8.8  -8.4  -8.   -7.6  -7.2  -6.8  -6.4  -6.   -5.6\n",
      "   -5.2  -4.8  -4.4  -4.   -3.6  -3.2  -2.8  -2.4  -2.   -1.6  -1.2  -0.8\n",
      "   -0.4   0.    0.4   0.8   1.2   1.6   2.    2.4   2.8   3.2   3.6   4.\n",
      "    4.4   4.8   5.2   5.6   6.    6.4   6.8   7.2   7.6   8.    8.4   8.8\n",
      "    9.2   9.6  10. ]]\n"
     ]
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from matplotlib import cm\n",
    "\n",
    "\n",
    "def f(x, y):\n",
    "    # sinc 函数\n",
    "    r = np.sqrt(x ** 2 + y ** 2)\n",
    "    result = np.sin(r) / r\n",
    "    result[r == 0] = 1.0\n",
    "    return result\n",
    "\n",
    "\n",
    "x_ticks = np.linspace(-10, 10, 51)\n",
    "y_ticks = np.linspace(-10, 10, 51)\n",
    "\n",
    "x, y = np.meshgrid(x_ticks, y_ticks, sparse=True)\n",
    "print(x)  # x, y 中有很多冗余的元素，这里提供了一个 sparse 的选项去冗余"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "234cd4dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-60-3339129a474e>:8: RuntimeWarning: invalid value encountered in true_divide\n",
      "  result = np.sin(r) / r\n"
     ]
    }
   ],
   "source": [
    "z = f(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "51bd8388",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "ax = fig.add_subplot(111, projection='3d')\n",
    "ax.plot_surface(x, y, z,\n",
    "                rstride=1, cstride=1,\n",
    "                cmap=cm.YlGnBu_r)\n",
    "ax.set_xlabel('x')\n",
    "ax.set_ylabel('y')\n",
    "ax.set_zlabel('z')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f761bd8",
   "metadata": {},
   "source": [
    "## 内存映射\n",
    "\n",
    "Numpy 有对内存映射的支持。\n",
    "\n",
    "内存映射也是一种处理文件的方法，主要的函数有：\n",
    "- memmap\n",
    "- frombuffer\n",
    "- ndarray constructor\n",
    "\n",
    "使用内存映射文件处理存储于磁盘上的文件时，将不必再对文件执行I/O操作，\n",
    "使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。\n",
    "```python\n",
    "memmap(filename,\n",
    "       dtype=uint8,\n",
    "       mode='r+'\n",
    "       offset=0\n",
    "       shape=None\n",
    "       order=0)\n",
    "```\n",
    "mode 表示文件被打开的类型：\n",
    "- r 只读\n",
    "- c 复制+写，但是不改变源文件\n",
    "- r+ 读写，使用 flush 方法会将更改的内容写入文件\n",
    "- w+ 写，如果存在则将数据覆盖\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c8f61f3",
   "metadata": {},
   "source": [
    "## 数组相加：add\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "61755e27",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]] [0 1]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([[1, 2], [3, 4]])\n",
    "b = np.arange(2)\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "6d076b19",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([1, 2]), array([3, 4]), 0, 1]\n"
     ]
    }
   ],
   "source": [
    "a_list = list(a)\n",
    "b_list = list(b)\n",
    "d = a_list + b_list\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b769fc7",
   "metadata": {},
   "source": [
    "extend："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "3cd2ceb1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "[array([1, 2]), array([3, 4]), 0, 1]\n",
      "[array([1, 2]) array([3, 4]) 0 1]\n"
     ]
    }
   ],
   "source": [
    "c = a_list.extend(b_list)\n",
    "print(c)\n",
    "\n",
    "print(a_list)\n",
    "\n",
    "print(np.array(a_list, dtype=object))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1297263",
   "metadata": {},
   "source": [
    "append："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "83eb9835",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 0, 1])"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.append(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "965cc34b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[0, 1]]"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k = []\n",
    "k.append(b_list)\n",
    "k"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "23a754db",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[0, 1], 1, 2]"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_list = [1, 2]\n",
    "k.extend(k_list)\n",
    "k"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63138192",
   "metadata": {},
   "source": [
    "本节完。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}